package network

import (
	"fmt"
	"net"
	"sync/atomic"
	"time"

	"gitee.com/doraemon1996/bunny/goroutine"
	"gitee.com/doraemon1996/bunny/structure"
	"gitee.com/doraemon1996/bunny/timer"
	"gitee.com/doraemon1996/bunny/uuid"
)

// TCP连接
type TCPConn struct {
	conn

	rawConn *net.TCPConn // 底层TCP连接
}

// 新建TCP连接
func NewTCPConn(ln Listener, rawConn *net.TCPConn) *TCPConn {
	tcp := new(TCPConn)
	tcp.id = uuid.GenUint64()
	tcp.ln = ln
	tcp.rawConn = rawConn
	return tcp
}

// 获取连接类型
func (conn *TCPConn) Type() ConnectionType {
	return Connection_TCP
}

// 获取连接概况
func (conn *TCPConn) String() string {
	return fmt.Sprintf("TCPConn[%X][%s<-->%s]", conn.id, conn.rawConn.LocalAddr().String(), conn.rawConn.RemoteAddr().String())
}

// 获取底层连接
func (conn *TCPConn) RawConn() net.Conn {
	return conn.rawConn
}

// 开始运行连接的消息处理逻辑
func (conn *TCPConn) Start(handler EventHandler) {
	if handler == nil {
		panic(ErrorEventHandlerInvalid)
	}

	conn.ctl.Start(func() {
		conn.eventHandler = handler

		// 开启定时任务
		if conn.crontabPeriod.Milliseconds() >= 1 {
			conn.crontabID = timer.Interval(conn.crontabPeriod, func() {
				conn.eventHandler.OnCrontab(conn)
			})
			if conn.crontabID == 0 {
				err := &networkError{ErrorType_Network, ErrorCrontabLuanchFailed}
				if conn.eventHandler.OnError(conn, err) {
					conn.Stop(err)
					return
				}
			}
		}

		conn.ctl.Add(2)
		goroutine.Submit(func() {
			err := conn.recvLoop()
			conn.ctl.Done()
			if conn.ctl.Opening() {
				conn.Stop(err)
			}
		})
		goroutine.Submit(func() {
			err := conn.sendLoop()
			conn.ctl.Done()
			if conn.ctl.Opening() {
				conn.Stop(err)
			}
		})
	})
}

// 停止并关闭连接
func (conn *TCPConn) Stop(err Error) {
	conn.ctl.Stop(func() {
		conn.rawConn.SetReadDeadline(time.Now())
		if conn.crontabID != 0 {
			timer.Remove(conn.crontabID)
			conn.crontabID = 0
		}

		conn.ctl.Wait()

		close(conn.sendChan)
		if conn.eventHandler != nil {
			conn.eventHandler.OnDisconnect(conn, err)
		}
		conn.rawConn.Close()
	})
}

// 发送消息
func (conn *TCPConn) Send(msg any) (err error) {
	if conn.ctl.Closed() {
		return &networkError{ErrorType_Network, ErrorConnectionClosed}
	}

	var (
		p           []byte // 消息编码后的二进制数据
		customerErr error  // Encode()函数返回的错误
	)

	p, customerErr = conn.eventHandler.Encode(conn, msg)
	if customerErr != nil {
		err = &networkError{ErrorType_Customer, customerErr}
		return
	}

	if len(p) < 1 {
		return &networkError{ErrorType_Network, ErrorMessageBufferSizeTooShort}
	}

	buf := bufferPool.Get()
	buf.Write(p)

	conn.sendChan <- buf

	return
}

// 从底层连接读取一次消息数据
func (conn *TCPConn) read(stream *structure.Buffer) (err Error) {
	var (
		buf           []byte // 读取到的二进制消息数据
		length        int    // 读取到的数据长度
		underlyingErr error  // net包返回的错误
	)
	defer func() {
		if val := recover(); val != nil {
			err = &networkError{ErrorType_Network, val}
		}
	}()

	buf = stream.WriteNextBegin(conn.readLimit)
	length, underlyingErr = conn.rawConn.Read(buf)
	if underlyingErr != nil {
		err = &networkError{ErrorType_Underlying, underlyingErr}
	}
	stream.WriteNextEnd(length)
	atomic.AddUint64(&conn.readBytes, uint64(length))

	return
}

// 处理消息数据
func (conn *TCPConn) handle(stream *structure.Buffer) (err Error) {
	var (
		msg         any   // 从二进制数据缓存中解码出的消息
		length      int   // 解码出的消息对应的二进制数据长度
		customerErr error // Decode()返回的错误
	)

	defer func() {
		if val := recover(); val != nil {
			err = &networkError{ErrorType_Customer, val}
		}
	}()

	for {
		if stream.Len() < 1 {
			break
		}

		msg, length, customerErr = conn.eventHandler.Decode(conn, stream.Bytes())
		// 优先丢弃已处理数据
		stream.Next(length)

		if msg == nil {
			break
		}

		if customerErr != nil {
			err = &networkError{ErrorType_Customer, customerErr}
			break
		}

		conn.eventHandler.OnMessage(conn, msg)
		atomic.AddUint64(&conn.readPackages, 1)
	}

	return
}

// 收消息循环
func (conn *TCPConn) recvLoop() (err Error) {
	var (
		stream  *structure.Buffer            // 从底层连接中读取出来的二进制数据缓存
		sample  structure.SampleCompare[int] // 用于释放长时间未使用的内存
		compare func(int) bool               // 采样数据比较函数
	)

	stream = bufferPool.Get()
	defer bufferPool.Put(stream)

	// 条件检测
	compare = func(i int) bool {
		return i < stream.Cap()/2
	}
	sample.SampleLen = 10

	for !conn.ctl.Closed() {
		err = conn.read(stream)
		if err != nil && !conn.ctl.Closed() && conn.eventHandler.OnError(conn, err) {
			break
		}

		// 采样每次读数据后的缓存使用最大值
		sample.SampleAdd(stream.Cap(), stream.Len())

		err = conn.handle(stream)
		if err != nil && !conn.ctl.Closed() && conn.eventHandler.OnError(conn, err) {
			break
		}

		// 获取采样结果
		if sample.Result(compare) {
			stream.AdjustCap(stream.Cap() / 2)
		}
	}
	return
}

// 拼接消息数据
func (conn *TCPConn) join(stream *structure.Buffer) (err Error) {
	var (
		length int               // 发送队列长度
		msg    *structure.Buffer // 已经编码的消息数据
	)

	defer func() {
		if val := recover(); val != nil {
			err = &networkError{ErrorType_Network, val}
		}
	}()

	length = len(conn.sendChan)
	for i := 0; i < length; i++ {
		msg = (<-conn.sendChan).(*structure.Buffer)
		_, bufferErr := msg.WriteTo(stream)
		bufferPool.Put(msg)

		if bufferErr == nil {
			atomic.AddUint64(&conn.writePackages, 1)
		} else {
			err = &networkError{ErrorType_Network, bufferErr}
			break
		}
	}

	return
}

// 将消息数据写到底层连接
func (conn *TCPConn) write(buf []byte) (err Error) {
	var (
		length        int   // 每次实际写入数据大小
		count         int   // 累计写入数据大小
		underlyingErr error // net包返回的错误
	)

	defer func() {
		if val := recover(); val != nil {
			err = &networkError{ErrorType_Underlying, val}
		}
	}()

	for len(buf) > 0 {
		data := buf
		if len(data) > conn.writeLimit {
			data = buf[:conn.writeLimit]
		}

		length, underlyingErr = conn.rawConn.Write(data)
		if underlyingErr != nil {
			err = &networkError{ErrorType_Underlying, underlyingErr}
			break
		}

		count += length
		buf = buf[length:]
	}

	if count > 0 {
		atomic.AddUint64(&conn.writeBytes, uint64(count))
	}

	return
}

// 发消息循环
func (conn *TCPConn) sendLoop() (err Error) {
	var (
		stream  *structure.Buffer            // 写入底层连接中的二进制数据缓存
		sample  structure.SampleCompare[int] // 缓存采样拥挤
		compare func(int) bool               // 采样数据比较函数
	)

	stream = bufferPool.Get()
	defer bufferPool.Put(stream)

	// 条件检测
	compare = func(i int) bool {
		return i < stream.Cap()/2
	}
	sample.SampleLen = 10

	for !conn.ctl.Closed() {
		err = conn.join(stream)
		if err != nil && !conn.ctl.Closed() && conn.eventHandler.OnError(conn, err) {
			break
		}

		// 采样每次拼接数据后的缓存使用最大值
		sample.SampleAdd(stream.Cap(), stream.Len())

		if stream.Len() > 0 {
			err = conn.write(stream.Bytes())
			stream.Reset()
			if err != nil && !conn.ctl.Closed() && conn.eventHandler.OnError(conn, err) {
				break
			}
		}

		// 有一半的缓存容量长时间不使用,则释放释放一半容量
		if sample.Result(compare) {
			stream.AdjustCap(stream.Cap() / 2)
		}
	}
	return
}
